package service

import (
	"fmt"
	"gitee.com/molonglove/goboot/gorm"
	"github.com/golang-jwt/jwt/v5"
	"gopkg.in/gomail.v2"
	"helper-api/app/constant"
	"helper-api/app/models/entity"
	"helper-api/app/models/request"
	"helper-api/app/models/response"
	"helper-api/app/models/vo"
	"helper-api/core"
	"helper-api/internal/cache"
	"helper-api/utils"
	"math/rand"
	"sort"
	"time"
)

var User = new(UserService)

type UserService struct{}

// Login 用户登录
func (u *UserService) Login(param *request.UserLoginRequest) (response.UserLoginResponse, *response.BusinessError) {
	var (
		buildTree     func(list []response.PermInfo, target *response.PermInfo) // 构建树
		generateToken = func(user *entity.User) (string, error) {
			claims := vo.UserClaims{
				UserId:   user.Id,
				Username: user.Username,
				Email:    user.Email,
				RegisteredClaims: jwt.RegisteredClaims{
					ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Duration(core.MockConfig.Jwt.ExpiresTime) * time.Hour)), // 过期时间
					IssuedAt:  jwt.NewNumericDate(time.Now()),                                                                 // 签发时间
					NotBefore: jwt.NewNumericDate(time.Now()),                                                                 // 生效时间
					Issuer:    core.MockConfig.Jwt.Issuer,
				},
			}
			t := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
			return t.SignedString([]byte(core.MockConfig.Jwt.SecretKey))
		} // 生成token信息
		roleIds = func(roles []response.RoleInfo) (ids []int64) {
			ids = make([]int64, 0)
			for _, item := range roles {
				ids = append(ids, item.Id)
			}
			return
		} // 构建角色ID
		filerSort = func(list []response.PermInfo, pId int64) []response.PermInfo {
			result := make([]response.PermInfo, 0)
			for _, info := range list {
				if info.ParentId == pId {
					result = append(result, info)
				}
			}
			sort.SliceStable(result, func(i, j int) bool {
				return result[i].OrderNo < result[j].OrderNo
			})
			return result
		}
		generateTree = func(list []response.PermInfo) []response.PermInfo {
			if len(list) <= 0 {
				return nil
			}
			result := filerSort(list, 0)
			for i := 0; i < len(result); i++ {
				buildTree(list, &result[i])
			}
			return result
		}

		result response.UserLoginResponse
		roles  []response.RoleInfo
		perms  []response.PermInfo
		tree   []response.PermInfo
		ids    []int64
		token  string
		user   entity.User
		err    error
	)

	buildTree = func(list []response.PermInfo, target *response.PermInfo) {
		children := filerSort(list, target.Id)
		if len(children) <= 0 {
			return
		}
		target.Children = children
		for i := 0; i < len(children); i++ {
			buildTree(list, &children[i])
		}
	} // 具体实现

	// 查询数据
	if err = core.DB.Model(&entity.User{}).
		Where("username = ? and can_view = 1", param.Username).
		First(&user).
		Error; err != nil {
		core.Log.Error("当前用户[%s]不存在: [%s]", param.Username, err.Error())
		return result, response.NewBusinessError(response.DataNotExist)
	}
	// 密码不正确
	if utils.TransformMd5(param.Password+user.Salt) != user.Password {
		core.Log.Error("当前用户密码[%s]不正确", param.Password)
		return result, response.NewBusinessError(response.UserPasswordError)
	}
	// 构建jwt
	if token, err = generateToken(&user); err != nil {
		core.Log.Error("生成认证Token错误:%s", err.Error())
		return result, response.NewBusinessError(response.TokenBuildError)
	}
	// 构建角色
	if err = core.DB.Model(&entity.Role{}).
		Select("s_role.id, s_role.name, s_role.code").
		Where("exists(select 1 from s_user_role where s_user_role.user_id = ? and s_user_role.role_id = s_role.id)", user.Id).
		Find(&roles).
		Error; err == nil {
		if ids = roleIds(roles); len(ids) > 0 {
			if err = core.DB.Debug().Model(&entity.Permission{}).
				Select("s_permission.id, s_permission.name, s_permission.code, s_permission.icon, s_permission.res_type as types, s_permission.parent_id, s_permission.level, s_permission.path, s_permission.order_no").
				Where("exists(select 1 from s_role_permission where s_role_permission.role_id in (?) and s_role_permission.perm_id = s_permission.id)", ids).
				Find(&perms).Error; err == nil {
				tree = generateTree(perms)
			}
		}
	}
	// 添加缓冲
	cache.MemeryCache.PushWithExpire(
		fmt.Sprintf("%s%d", constant.UserKey, user.Id),
		token,
		int64(time.Duration(core.MockConfig.Jwt.ExpiresTime)*time.Hour),
	)
	// 返回数据
	return response.UserLoginResponse{
		UserId:   user.Id,
		Username: user.Username,
		Email:    user.Email,
		Token:    token,
		Roles:    roles,
		Perms:    tree,
	}, nil
}

// Logout 退出登录
func (u *UserService) Logout(id int64) *response.BusinessError {
	cache.MemeryCache.Delete(fmt.Sprintf("%s%d", constant.UserKey, id))
	core.WS.Remove(id)
	return nil
}

// Register 注册
func (u *UserService) Register(param *request.UserRegisterRequest) *response.BusinessError {
	var (
		user     *entity.User
		code     any
		isExpire bool
		total    int64
		err      error
	)
	// 判断验证码是否正确
	if isExpire, code = cache.MemeryCache.Get(param.Email); isExpire {
		return response.NewBusinessError(response.CaptchaExpire)
	}
	// 验证码错误
	if param.Captcha != code.(string) {
		return response.NewBusinessError(response.CaptchaError)
	}
	defer cache.MemeryCache.Delete(param.Email)
	// 判断账户名称是否存在
	if err = core.DB.Model(&entity.User{}).
		Where("username = ?", param.Username).
		Count(&total).
		Error; err != nil || total > 0 {
		return response.NewBusinessError(response.UserNameExist)
	}
	// 判断邮箱是否已经被注册了
	if err = core.DB.Model(&entity.User{}).
		Where("email = ?", param.Username).
		Count(&total).
		Error; err != nil || total > 0 {
		return response.NewBusinessError(response.EmailExist)
	}
	user = &entity.User{
		Username:   param.Username,
		Password:   utils.TransformMd5(param.Password + constant.UserSalt),
		Salt:       constant.UserSalt,
		Email:      param.Email,
		CreateTime: time.Now(),
	}
	if err = core.DB.Create(user).Error; err != nil {
		return response.NewBusinessError(response.AddDataError)
	}
	core.Log.Info("注册用户成功 => %v", param)
	return nil
}

// sendEmail 发送邮箱
func (u *UserService) sendEmail(email string, title string, content string) error {
	var (
		emailConfig core.Email
		mail        *gomail.Message
		dialer      *gomail.Dialer
	)
	emailConfig = core.MockConfig.Email

	mail = gomail.NewMessage()
	mail.SetHeader("From", emailConfig.Form)
	mail.SetHeader("To", email)
	mail.SetHeader("Subject", title)
	mail.SetBody("text/html", content)

	dialer = gomail.NewDialer(emailConfig.Host, emailConfig.Port, emailConfig.Form, emailConfig.Auth)

	// Send the email
	return dialer.DialAndSend(mail)
}

// SendEmail 发送邮箱验证码
func (u *UserService) SendEmail(email string) *response.BusinessError {
	var (
		emailConfig core.Email
		random      *rand.Rand
		code        string
		content     string
		mail        *gomail.Message
		dialer      *gomail.Dialer
		err         error
	)
	random = rand.New(rand.NewSource(time.Now().Unix()))
	code = fmt.Sprintf("%06v", random.Int31n(1000000))
	core.Log.Info("生成的验证码: %s", code)

	content = fmt.Sprintf(`<div>
    <p>本次验证码为 <span style="color: #0958d9">%s</span>，为了保证账号安全，验证码有效期为5分钟。请确认为本人操作，切勿向他人泄露，感谢您的理解与使用。</p>
</div>`, code)

	emailConfig = core.MockConfig.Email

	mail = gomail.NewMessage()
	mail.SetHeader("From", emailConfig.Form)
	mail.SetHeader("To", email)
	mail.SetHeader("Subject", "验证您注册电子邮箱地址")
	mail.SetBody("text/html", content)

	dialer = gomail.NewDialer(emailConfig.Host, emailConfig.Port, emailConfig.Form, emailConfig.Auth)

	// Send the email
	if err = dialer.DialAndSend(mail); err != nil {
		core.Log.Info("发送验证码失败: %s", err.Error())
		return response.NewBusinessError(response.EmailSendError)
	}
	// 写入缓冲
	cache.MemeryCache.PushWithExpire(email, code, 5*60)

	return nil
}

// UserPage 用户分页
func (u *UserService) UserPage(param request.UserPageRequest) (*response.PageData, *response.BusinessError) {
	var (
		err      error
		tx       *gorm.DB
		total    int64
		records  []response.UserListResponse
		result   *response.PageData
		userRole []response.UserRoleResponse
		userIds  []int64
		filter   = func(userId int64, userRole []response.UserRoleResponse) []response.UserRoleResponse {
			end := make([]response.UserRoleResponse, 0)
			for _, item := range userRole {
				if item.UserId == userId {
					end = append(end, item)
				}
			}
			return end
		}
	)
	tx = core.DB.Model(&entity.User{}).Where("can_view = 1")
	if param.Name != "" {
		tx.Where("name = ?", param.Name)
	}
	if err = tx.Count(&total).Error; err != nil {
		core.Log.Error("统计SQL执行错误 => %s", err.Error())
		return result, response.NewBusinessError(response.SqlExecuteError)
	}
	if total != 0 {
		tx = core.DB.Model(&entity.User{})
		if param.Name != "" {
			tx.Where("name = ?", param.Name)
		}
		if err = tx.Where("can_view = 1").
			Order("create_time").
			Offset(param.Offset()).
			Limit(param.Size).
			Find(&records).
			Error; err != nil {
			core.Log.Error("SQL执行错误 => %s", err.Error())
			return result, response.NewBusinessError(response.SqlExecuteError)
		}
		userIds = make([]int64, 0)
		for _, item := range records {
			userIds = append(userIds, item.Id)
		}
		if err = core.DB.Debug().Model(&entity.UserRole{}).
			Select("s_user_role.role_id as id,s_user_role.user_id,(select s_role.name from s_role where s_role.id = s_user_role.role_id) as name").
			Where("s_user_role.user_id in (?)", userIds).
			Find(&userRole).
			Error; err != nil {
			core.Log.Error("查询用户角色失败 => %s", err.Error())
			return result, response.NewBusinessError(response.SqlExecuteError)
		}
		// 获取用户角色信息
		if len(userRole) > 0 {
			for i := 0; i < len(records); i++ {
				records[i].UserRole = filter(records[i].Id, userRole)
			}
		}
	}
	result = response.NewPageData(param.Page, param.Size, total, records)
	return result, nil
}

// UserDetail 获取用户详情
func (u *UserService) UserDetail(id int64) (*response.UserDetailResponse, *response.BusinessError) {
	var (
		result *response.UserDetailResponse
		user   entity.User
		err    error
	)
	if err = core.DB.Debug().Model(&entity.User{}).
		Where("id = ? and can_view = 1", id).
		First(&user).
		Error; err != nil {
		return nil, response.NewBusinessError(response.DataNotExist)
	}

	result = &response.UserDetailResponse{
		Id:         user.Id,
		Name:       user.Username,
		Phone:      user.Phone,
		Email:      user.Email,
		Sex:        user.Sex,
		Desc:       user.Desc,
		UserStatus: user.UserStatus,
		RoleIds:    make([]int64, 0),
		PermIds:    make([]int64, 0),
	}

	// 获取用户角色信息
	err = core.DB.Debug().Model(&entity.UserRole{}).
		Select("distinct s_user_role.role_id").
		Where("s_user_role.user_id = ?", id).
		Find(&result.RoleIds).
		Error
	// 获取拥有角色资源
	err = core.DB.Debug().Model(&entity.RolePermission{}).
		Select("distinct s_role_permission.perm_id").
		Where("s_role_permission.role_id in (?)", result.RoleIds).
		Find(&result.PermIds).
		Error
	if err != nil {
		return nil, response.CustomBusinessError(response.Failed, err.Error())
	}
	return result, nil
}

// Update 更新
func (u *UserService) Update(param *request.UserUpdateRequest) *response.BusinessError {
	var (
		tx        *gorm.DB
		user      entity.User
		userRoles []entity.UserRole
		err       error
	)
	tx = core.DB.Begin()
	defer func() {
		if err != nil {
			tx.Rollback()
		} else {
			tx.Commit()
		}
	}()
	if err = tx.Model(&entity.User{}).
		Where("can_view = 1 and id = ?", param.Id).
		Find(&user).
		Error; err != nil {
		core.Log.Error("获取用户信息失败: %s", err.Error())
		return response.NewBusinessError(response.DataNotExist)
	}

	user.Username, user.Phone, user.Email, user.UserStatus, user.Sex, user.Desc, user.UpdateId, user.UpdateTime = param.Name, param.Phone, param.Email, param.UserStatus, param.Sex, param.Desc, param.UserId, time.Now()
	if err = tx.Save(&user).Error; err != nil {
		core.Log.Error("更新用户信息失败: %s", err.Error())
		return response.NewBusinessError(response.UserUpdateError)
	}

	if len(param.RoleId) > 0 {
		userRoles = make([]entity.UserRole, 0)
		for _, item := range param.RoleId {
			userRoles = append(userRoles, entity.UserRole{
				UserId: user.Id,
				RoleId: item,
			})
		}
		if err = tx.Where("user_id = ?", user.Id).Delete(&entity.UserRole{}).Error; err != nil {
			return response.NewBusinessError(response.UserAuthRoleError)
		}
		if err = tx.CreateInBatches(&userRoles, len(userRoles)).Error; err != nil {
			return response.NewBusinessError(response.UserAuthRoleError)
		}
	}
	return nil
}

// ResetPassword 重置密码
func (u *UserService) ResetPassword(id int64, userId int64) *response.BusinessError {
	var (
		password string
		content  string
		user     entity.User
		err      error
	)
	if err = core.DB.Model(&entity.User{}).
		Where("id = ? and can_view = 1", id).
		First(&user).
		Error; err != nil {
		return response.NewBusinessError(response.DataNotExist)
	}
	password = utils.RandomString(8)
	user.Password, user.UpdateId, user.UpdateTime = utils.TransformMd5(password+constant.UserSalt), userId, time.Now()
	if err = core.DB.Save(&user).Error; err != nil {
		return response.NewBusinessError(response.UserAuthRoleError)
	}
	content = fmt.Sprintf(`<div>
    <p>您的系统登录密码重置为: <span style="color: #0958d9">%s</span>，为了保证账号安全，请勿将密码提供给其他的人使用。感谢您的理解与使用。</p>
</div>`, password)
	if err = u.sendEmail(user.Email, "密码重置通知", content); err != nil {
		core.Log.Info("发送密码重置邮件失败: %s", err.Error())
		return response.NewBusinessError(response.EmailSendError)
	}
	return nil
}

// DeleteUser 删除用户
func (u *UserService) DeleteUser(ids []int64, id int64) *response.BusinessError {
	if err := core.DB.Model(&entity.User{}).
		Where("id in ?", ids).
		Updates(map[string]interface{}{"update_id": id, "update_time": time.Now(), "can_view": 0}).
		Error; err != nil {
		core.Log.Error("执行SQL删除错误 => %s", err.Error())
		return response.NewBusinessError(response.UserDeleteError)
	}
	return nil
}
